﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using LayeredArchitectureSample.Infrastructure;
using LayeredArchitectureSample.Infrastructure.Services;
using LayeredArchitectureSample.ServiceContracts;

namespace LayeredArchitectureSample.ViewModel
{
    internal class WaresViewModel : INotifyPropertyChanged
    {
        private readonly IServiceOperationInvoker<IRemoteWareRepository> _remoteRepository;

        private readonly ObservableCollection<WareViewModel> _wares;
        private WareViewModel _currentlySelectedWare;
        private bool _isSomethingSelected;
        private readonly IApplicationController _applicationController;
        private readonly IExceptionAwareServiceCodeRunner _codeRunner;
        private readonly string _somethingSelectedPropertyName;
        private readonly string _warePropertyName;

        public WaresViewModel(
            IEnumerable<WareViewModel> wares,
            IServiceOperationInvoker<IRemoteWareRepository> remoteRepository,
            IApplicationController applicationController,
            IExceptionAwareServiceCodeRunner codeRunner)
        {
            if (wares == null) throw new ArgumentNullException("wares");
            if (remoteRepository == null) throw new ArgumentNullException("remoteRepository");
            if (applicationController == null) throw new ArgumentNullException("applicationController");
            if (codeRunner == null) throw new ArgumentNullException("codeRunner");

            _remoteRepository = remoteRepository;
            _applicationController = applicationController;
            _codeRunner = codeRunner;
            _wares = new ObservableCollection<WareViewModel>(wares);

            _somethingSelectedPropertyName = Reflection.GetPropertyName(() => this.IsSomethingSelected);
            _warePropertyName = Reflection.GetPropertyName(() => this.CurrentlySelectedWare);
        }

        public ObservableCollection<WareViewModel> Wares
        {
            get { return _wares; }
        }

        public WareViewModel CurrentlySelectedWare
        {
            get { return _currentlySelectedWare; }
            set
            {
                _currentlySelectedWare = value;

                this.IsSomethingSelected = (_currentlySelectedWare != null);
                EventRaiser.RaisePropertyChangedEvent(PropertyChanged, this, _warePropertyName);
            }
        }

        public bool IsSomethingSelected
        {
            get {
                return _isSomethingSelected;
            }
            set {
                _isSomethingSelected = value;
                EventRaiser.RaisePropertyChangedEvent(PropertyChanged, this, _somethingSelectedPropertyName);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void RemoveSelectedWare()
        {
            _codeRunner.RunCode(() =>
                                    {
                                        _remoteRepository.Invoke(x => x.RemoveWare(CurrentlySelectedWare.Id));

                                        _wares.Remove(CurrentlySelectedWare);

                                        CurrentlySelectedWare = null;
                                    });
        }

        public void AddNewWare()
        {
            var viewModel = new NewWareViewModel(_remoteRepository, _codeRunner);

            _applicationController.ShowNewWareWindow(viewModel);

            if (viewModel.CreatedNewWare)
            {
                WareViewModel newlyCreatedWare = viewModel.GetNewlyCreatedWare();

                _wares.Add(newlyCreatedWare);
            }
        }
    }
}